package basics.collections;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * Java 集合与数组对比示例
 * 
 * 本类展示了Java集合与数组的区别、各自优缺点以及适用场景
 */
public class CollectionVsArrayDemo {
    
    public static void main(String[] args) {
        System.out.println("===== Java 集合与数组对比 =====");
        
        // 基本特性对比
        basicFeatureComparison();
        
        // 性能对比
        performanceComparison();
        
        // 功能对比
        functionalityComparison();
        
        // 内存占用对比
        memoryUsageComparison();
        
        // 适用场景对比
        useCaseComparison();
    }
    
    /**
     * 基本特性对比
     */
    private static void basicFeatureComparison() {
        System.out.println("\n----- 基本特性对比 -----");
        
        // 数组特性
        System.out.println("数组特性:");
        System.out.println("1. 固定长度，一旦创建不能改变大小");
        System.out.println("2. 可以存储基本类型和引用类型");
        System.out.println("3. 通过索引直接访问元素");
        System.out.println("4. 内存连续分配");
        System.out.println("5. 没有内置方法，需要借助Arrays工具类");
        
        // 集合特性
        System.out.println("\n集合特性:");
        System.out.println("1. 动态大小，可以根据需要增长或缩小");
        System.out.println("2. 只能存储对象，不能存储基本类型（需要使用包装类）");
        System.out.println("3. 提供了丰富的API和操作方法");
        System.out.println("4. 支持泛型，提供类型安全");
        System.out.println("5. 有多种实现类，适用于不同场景");
        
        // 示例：创建和初始化
        System.out.println("\n创建和初始化示例:");
        
        // 数组
        int[] intArray = new int[5]; // 固定大小
        intArray[0] = 1;
        intArray[1] = 2;
        
        String[] stringArray = {"Java", "Python", "C++"}; // 使用数组字面量
        
        // 集合
        List<Integer> intList = new ArrayList<>(); // 动态大小
        intList.add(1);
        intList.add(2);
        
        List<String> stringList = new ArrayList<>();
        stringList.add("Java");
        stringList.add("Python");
        stringList.add("C++");
        
        System.out.println("int数组: " + Arrays.toString(intArray));
        System.out.println("String数组: " + Arrays.toString(stringArray));
        System.out.println("Integer集合: " + intList);
        System.out.println("String集合: " + stringList);
    }
    
    /**
     * 性能对比
     */
    private static void performanceComparison() {
        System.out.println("\n----- 性能对比 -----");
        
        final int SIZE = 1000000;
        
        // 创建数组和ArrayList
        int[] array = new int[SIZE];
        List<Integer> list = new ArrayList<>(SIZE);
        
        // 填充数据
        for (int i = 0; i < SIZE; i++) {
            array[i] = i;
            list.add(i);
        }
        
        // 随机访问性能
        System.out.println("随机访问性能测试（读取100万个元素）:");
        
        // 数组随机访问
        long startArray = System.nanoTime();
        int sumArray = 0;
        for (int i = 0; i < SIZE; i++) {
            sumArray += array[i];
        }
        long endArray = System.nanoTime();
        
        // ArrayList随机访问
        long startList = System.nanoTime();
        int sumList = 0;
        for (int i = 0; i < SIZE; i++) {
            sumList += list.get(i);
        }
        long endList = System.nanoTime();
        
        System.out.println("数组随机访问耗时: " + (endArray - startArray) / 1000000.0 + " 毫秒");
        System.out.println("ArrayList随机访问耗时: " + (endList - startList) / 1000000.0 + " 毫秒");
        
        // 插入性能（在开头插入元素）
        System.out.println("\n插入性能测试（在开头插入1000个元素）:");
        
        // 数组插入
        int[] originalArray = new int[1000];
        Arrays.fill(originalArray, 1);
        
        long startArrayInsert = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            int[] newArray = new int[originalArray.length + 1];
            newArray[0] = i;
            System.arraycopy(originalArray, 0, newArray, 1, originalArray.length);
            originalArray = newArray;
        }
        long endArrayInsert = System.nanoTime();
        
        // ArrayList插入
        List<Integer> originalList = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            originalList.add(1);
        }
        
        long startListInsert = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            originalList.add(0, i);
        }
        long endListInsert = System.nanoTime();
        
        System.out.println("数组插入耗时: " + (endArrayInsert - startArrayInsert) / 1000000.0 + " 毫秒");
        System.out.println("ArrayList插入耗时: " + (endListInsert - startListInsert) / 1000000.0 + " 毫秒");
        
        // 遍历性能
        System.out.println("\n遍历性能测试（遍历100万个元素）:");
        
        // 数组遍历（传统for循环）
        long startArrayTraverse1 = System.nanoTime();
        int sum1 = 0;
        for (int i = 0; i < array.length; i++) {
            sum1 += array[i];
        }
        long endArrayTraverse1 = System.nanoTime();
        
        // 数组遍历（增强for循环）
        long startArrayTraverse2 = System.nanoTime();
        int sum2 = 0;
        for (int value : array) {
            sum2 += value;
        }
        long endArrayTraverse2 = System.nanoTime();
        
        // ArrayList遍历（传统for循环）
        long startListTraverse1 = System.nanoTime();
        int sum3 = 0;
        for (int i = 0; i < list.size(); i++) {
            sum3 += list.get(i);
        }
        long endListTraverse1 = System.nanoTime();
        
        // ArrayList遍历（增强for循环）
        long startListTraverse2 = System.nanoTime();
        int sum4 = 0;
        for (int value : list) {
            sum4 += value;
        }
        long endListTraverse2 = System.nanoTime();
        
        // ArrayList遍历（迭代器）
        long startListTraverse3 = System.nanoTime();
        int sum5 = 0;
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            sum5 += iterator.next();
        }
        long endListTraverse3 = System.nanoTime();
        
        System.out.println("数组遍历（传统for）耗时: " + (endArrayTraverse1 - startArrayTraverse1) / 1000000.0 + " 毫秒");
        System.out.println("数组遍历（增强for）耗时: " + (endArrayTraverse2 - startArrayTraverse2) / 1000000.0 + " 毫秒");
        System.out.println("ArrayList遍历（传统for）耗时: " + (endListTraverse1 - startListTraverse1) / 1000000.0 + " 毫秒");
        System.out.println("ArrayList遍历（增强for）耗时: " + (endListTraverse2 - startListTraverse2) / 1000000.0 + " 毫秒");
        System.out.println("ArrayList遍历（迭代器）耗时: " + (endListTraverse3 - startListTraverse3) / 1000000.0 + " 毫秒");
    }
    
    /**
     * 功能对比
     */
    private static void functionalityComparison() {
        System.out.println("\n----- 功能对比 -----");
        
        // 数组功能
        System.out.println("数组功能:");
        int[] array = {5, 2, 9, 1, 7};
        
        // 排序
        Arrays.sort(array);
        System.out.println("排序后的数组: " + Arrays.toString(array));
        
        // 二分查找
        int index = Arrays.binarySearch(array, 5);
        System.out.println("5在数组中的索引: " + index);
        
        // 填充
        int[] filledArray = new int[5];
        Arrays.fill(filledArray, 10);
        System.out.println("填充后的数组: " + Arrays.toString(filledArray));
        
        // 集合功能
        System.out.println("\n集合功能:");
        List<Integer> list = new ArrayList<>();
        list.add(5);
        list.add(2);
        list.add(9);
        list.add(1);
        list.add(7);
        
        // 排序
        Collections.sort(list);
        System.out.println("排序后的List: " + list);
        
        // 二分查找
        int listIndex = Collections.binarySearch(list, 5);
        System.out.println("5在List中的索引: " + listIndex);
        
        // 反转
        Collections.reverse(list);
        System.out.println("反转后的List: " + list);
        
        // 打乱
        Collections.shuffle(list);
        System.out.println("打乱后的List: " + list);
        
        // 最大值和最小值
        int max = Collections.max(list);
        int min = Collections.min(list);
        System.out.println("最大值: " + max + ", 最小值: " + min);
        
        // 集合特有功能
        System.out.println("\n集合特有功能:");
        
        // 动态添加和删除元素
        list.add(10);
        System.out.println("添加元素后: " + list);
        
        list.remove(Integer.valueOf(2));
        System.out.println("删除元素2后: " + list);
        
        // 批量操作
        List<Integer> otherList = Arrays.asList(1, 5, 10);
        list.retainAll(otherList); // 保留共有元素
        System.out.println("保留共有元素后: " + list);
        
        // 类型安全（泛型）
        List<String> stringList = new ArrayList<>();
        stringList.add("Java");
        // stringList.add(123); // 编译错误，类型不匹配
        
        // 函数式操作（Java 8+）
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        List<Integer> evenNumbers = numbers.stream()
            .filter(n -> n % 2 == 0)
            .collect(Collectors.toList());
        
        System.out.println("过滤出偶数: " + evenNumbers);
        
        List<Integer> squaredNumbers = numbers.stream()
            .map(n -> n * n)
            .collect(Collectors.toList());
        
        System.out.println("映射为平方值: " + squaredNumbers);
    }
    
    /**
     * 内存占用对比
     */
    private static void memoryUsageComparison() {
        System.out.println("\n----- 内存占用对比 -----");
        
        System.out.println("内存占用比较（理论分析）:");
        System.out.println("1. 基本类型数组: 最节省内存，直接存储值");
        System.out.println("   例如: int[] 数组中每个元素占4字节");
        
        System.out.println("2. 包装类型数组: 每个元素是一个对象引用");
        System.out.println("   例如: Integer[] 数组中每个元素是一个指向Integer对象的引用");
        
        System.out.println("3. ArrayList<Integer>: 额外开销包括:");
        System.out.println("   - 内部数组的引用");
        System.out.println("   - 容量管理的字段");
        System.out.println("   - 每个元素都是Integer对象");
        System.out.println("   - 可能有未使用的容量");
        
        // 示例：创建大型数组和集合
        final int SIZE = 10000000;
        
        // 测量前的内存使用
        System.gc();
        long beforeArray = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        
        // 创建基本类型数组
        int[] intArray = new int[SIZE];
        for (int i = 0; i < SIZE; i++) {
            intArray[i] = i;
        }
        
        // 测量数组后的内存使用
        System.gc();
        long afterArray = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        
        // 清除数组引用
        intArray = null;
        System.gc();
        
        // 测量前的内存使用
        long beforeList = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        
        // 创建ArrayList
        List<Integer> intList = new ArrayList<>(SIZE);
        for (int i = 0; i < SIZE; i++) {
            intList.add(i);
        }
        
        // 测量ArrayList后的内存使用
        System.gc();
        long afterList = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        
        // 计算内存使用差异
        long arrayMemory = afterArray - beforeArray;
        long listMemory = afterList - beforeList;
        
        System.out.println("\n实际内存使用（近似值）:");
        System.out.println("int[]数组（" + SIZE + "个元素）: " + (arrayMemory / (1024 * 1024)) + " MB");
        System.out.println("ArrayList<Integer>（" + SIZE + "个元素）: " + (listMemory / (1024 * 1024)) + " MB");
        System.out.println("内存使用比例（ArrayList/数组）: " + String.format("%.2f", (double)listMemory / arrayMemory));
    }
    
    /**
     * 适用场景对比
     */
    private static void useCaseComparison() {
        System.out.println("\n----- 适用场景对比 -----");
        
        System.out.println("数组适用场景:");
        System.out.println("1. 固定大小的数据集合");
        System.out.println("2. 对性能要求极高的场景");
        System.out.println("3. 存储基本数据类型时（避免装箱/拆箱开销）");
        System.out.println("4. 多维数据结构（如矩阵）");
        System.out.println("5. 与底层API交互（如图形处理、网络I/O缓冲区）");
        
        System.out.println("\n集合适用场景:");
        System.out.println("1. 需要动态调整大小的数据集合");
        System.out.println("2. 需要复杂数据操作（排序、搜索、过滤等）");
        System.out.println("3. 需要特定数据结构（如队列、栈、集合、映射等）");
        System.out.println("4. 需要类型安全和泛型支持");
        System.out.println("5. 需要使用函数式编程特性（如Stream API）");
        
        // 示例：矩阵乘法（适合数组）
        System.out.println("\n示例1：矩阵乘法（适合数组）");
        int[][] matrixA = {{1, 2}, {3, 4}};
        int[][] matrixB = {{5, 6}, {7, 8}};
        int[][] result = new int[2][2];
        
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                for (int k = 0; k < 2; k++) {
                    result[i][j] += matrixA[i][k] * matrixB[k][j];
                }
            }
        }
        
        System.out.println("矩阵A:");
        printMatrix(matrixA);
        System.out.println("矩阵B:");
        printMatrix(matrixB);
        System.out.println("结果矩阵:");
        printMatrix(result);
        
        // 示例：单词频率统计（适合集合）
        System.out.println("\n示例2：单词频率统计（适合集合）");
        String text = "Java is a programming language. Java is widely used. Programming in Java is fun.";
        String[] words = text.toLowerCase().replaceAll("[^a-zA-Z ]", "").split("\\s+");
        
        Map<String, Integer> wordFrequency = new HashMap<>();
        for (String word : words) {
            wordFrequency.put(word, wordFrequency.getOrDefault(word, 0) + 1);
        }
        
        System.out.println("文本: " + text);
        System.out.println("单词频率:");
        wordFrequency.forEach((word, count) -> System.out.println(word + ": " + count));
        
        // 示例：数据过滤和转换（适合集合+Stream API）
        System.out.println("\n示例3：数据过滤和转换（适合集合+Stream API）");
        List<Integer> numbers = IntStream.rangeClosed(1, 20).boxed().collect(Collectors.toList());
        
        List<Integer> processedNumbers = numbers.stream()
            .filter(n -> n % 2 == 0)      // 过滤偶数
            .map(n -> n * n)              // 计算平方
            .filter(n -> n > 50)          // 过滤大于50的结果
            .collect(Collectors.toList());
        
        System.out.println("原始数字: " + numbers);
        System.out.println("处理后的数字: " + processedNumbers);
    }
    
    /**
     * 打印矩阵的辅助方法
     */
    private static void printMatrix(int[][] matrix) {
        for (int[] row : matrix) {
            System.out.println(Arrays.toString(row));
        }
    }
} 